package com.jg.visitor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jg.visitor.GlobalConst;
import com.jg.visitor.common.bean.ServiceCode;
import com.jg.visitor.common.utils.DateTimeUtil;
import com.jg.visitor.common.utils.JsonService;
import com.jg.visitor.common.utils.StringUtils;
import com.jg.visitor.config.autoconfiguration.caffeinecache.service.CacheService;
import com.jg.visitor.config.exception.BaseException;
import com.jg.visitor.config.exception.JgException;
import com.jg.visitor.controller.dto.*;
import com.jg.visitor.controller.enums.VisitorApplyRecordStatusEnum;
import com.jg.visitor.controller.enums.VisitorRecordOperationEnum;
import com.jg.visitor.controller.vo.CarInformationVO;
import com.jg.visitor.controller.vo.SignInOutVo;
import com.jg.visitor.domain.*;
import com.jg.visitor.service.*;
import com.jg.visitor.mapper.VisitorApplyRecordMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author Administrator
* 针对表【visitor_apply_record】的数据库操作Service实现
* 2022-04-25 23:43:26
*/
@Service
public class VisitorApplyRecordServiceImpl extends ServiceImpl<VisitorApplyRecordMapper, VisitorApplyRecord>
    implements VisitorApplyRecordService{
    @Resource
    private SignRecordService signRecordService;
    @Resource
    private FileUploadRecordService fileUploadRecordService;
    @Resource
    private OperationRecordService operationRecordService;
    @Resource
    private CacheService cacheService;
    @Resource
    private JsonService jsonService;
    @Resource
    private HealthInfoService healthInfoService;
    @Resource
    private VisitorInfoService visitorInfoService;

    @Override
    public VisitorApplyRecordDTO getVisitorApplyRecordDTOByVisitorApplyRecord(VisitorApplyRecord visitorApplyRecord,
                                                                              List<HealthInfo> healthInfoList,
                                                                              List<FileUploadRecord> fileUploadRecordList,
                                                                              List<OperationRecord> refuseRecordList,
                                                                              List<SignRecord> allSignRecord){
        //申请记录copy到dto
        VisitorApplyRecordDTO visitorApplyRecordDTO = new VisitorApplyRecordDTO();
        BeanUtils.copyProperties(visitorApplyRecord,visitorApplyRecordDTO);

        //找到自己的健康信息
        HealthInfo health = healthInfoList
                .stream()
                .filter(healthInfo -> healthInfo.getId().equals(visitorApplyRecord.getHealthInfoId()))
                .findAny()
                .orElse(null);

        //copy到dto
        if (health != null) {
            BeanUtils.copyProperties(health, visitorApplyRecordDTO);
            //设置图片信息
            visitorApplyRecordDTO.setHealthPicturePath(fileUploadRecordService.getFilePathById(fileUploadRecordList, health.getHealthPictureId()));
            visitorApplyRecordDTO.setNucleicPicturePath(fileUploadRecordService.getFilePathById(fileUploadRecordList, health.getNucleicPictureId()));
            visitorApplyRecordDTO.setTripPicturePath(fileUploadRecordService.getFilePathById(fileUploadRecordList, health.getTripPictureId()));
        }

        //如果有被拒绝则需要找到被拒绝原因
        if(GlobalConst.VISITOR_APPLY_RECORD_REFUSED.contains(visitorApplyRecord.getStatus())){
            OperationRecord refusedRecord = refuseRecordList
                    .stream()
                    .filter(operationRecord -> GlobalConst.REFUSE.equals(operationRecord.getApplyFlag())
                            && operationRecord.getApplyRecordId().equals(visitorApplyRecord.getId()))
                    .findAny()
                    .orElse(null);
            visitorApplyRecordDTO.setRemark(refusedRecord == null ? "" : refusedRecord.getRemark());
        }

        //找到签到签退记录
        List<OutInHistoryDTO.SignInOutDTO> signInOutList = allSignRecord
                .stream()
                .filter(signRecord -> signRecord.getVisitorApplyId().equals(visitorApplyRecord.getId()))
                .map(signRecord -> {
                    OutInHistoryDTO.SignInOutDTO dto = new OutInHistoryDTO.SignInOutDTO();
                    BeanUtils.copyProperties(signRecord, dto);
                    return dto;
                })
                .sorted(Comparator.comparing(o -> DateTimeUtil.getDateByStr(o.getSignTime())))
                .collect(Collectors.toList());
        visitorApplyRecordDTO.setSignInOutList(signInOutList);


        //健康信息被copy进来了重新设置id
        visitorApplyRecordDTO.setId(visitorApplyRecord.getId());
        return visitorApplyRecordDTO;
    }

    @Override
    public List<OperationRecord> getRefuseRecordList(List<VisitorApplyRecord> dataList) {
        List<Long> refusedIdList = dataList
                .stream()
                .filter(visitorApplyRecord -> VisitorApplyRecordStatusEnum.RESPONDENTS_REFUSE
                        .getStatusCode().equals(visitorApplyRecord.getStatus()) ||
                        VisitorApplyRecordStatusEnum.SAFER_REFUSE.getStatusCode().equals(visitorApplyRecord.getStatus()))
                .map(VisitorApplyRecord::getId)
                .collect(Collectors.toList());

        return CollectionUtils.isEmpty(refusedIdList) ? new ArrayList<>() :
                operationRecordService.list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApproverApproveRecordDTO signInOut(SignInOutVo signInOutVo) {
        if(StringUtils.isEmpty(signInOutVo.getKey())){
            throw new JgException(ServiceCode.BAD_REQUEST);
        }

        if(signInOutVo.getOperationType() == null){
            signInOutVo.setOperationType(SignInOutVo.OperationEnum.SIGN_IN.getType());
        }

        if(StringUtils.isEmpty(signInOutVo.getDoor())){
            signInOutVo.setDoor("");
        }

        String key = signInOutVo.getKey();

        if(StringUtils.isEmpty(key)){
            throw new BaseException(-1,"签到key异常！");
        }


        Object cache = cacheService.getCache(GlobalConst.VISITOR_PASS_CODE, key, Object.class);
        if(null == cache){
            throw new BaseException(-1,"通行码无效或已过期！");
        }


        String jsonResult = jsonService.objectToJson(cacheService.getCache(GlobalConst.VISITOR_PASS_CODE, key, VisitorApplyRecord.class));
        VisitorApplyRecord passedOrder = jsonService.jsonToObject(jsonResult,VisitorApplyRecord.class);

        //访客信息
        VisitorInfo visitor = visitorInfoService.getById(passedOrder.getVisitorInfoId());

        //已经超过申请的结束时间则不能操作签到签退
        if(DateTimeUtil.getDateByStr(DateTimeUtil.getTimeNow()).getTime() > DateTimeUtil.getDateByStr(passedOrder.getEndTime()).getTime()){
            throw new BaseException(-1,"已超过访问结束时间不能进行操作！");
        }

        //操作记录
        OperationRecord operationRecord = new OperationRecord();
        operationRecord.setOldStatus(passedOrder.getStatus());
        operationRecord.setNewStatus(passedOrder.getStatus());

        //签到签退记录
        SignRecord signRecord = new SignRecord();
        signRecord.setDoor(signInOutVo.getDoor());
        signRecord.setSignTime(DateTimeUtil.getTimeNow());
        signRecord.setVisitorApplyId(passedOrder.getId());
        signRecord.setVisitorId(passedOrder.getVisitorInfoId());

        //签到
        if(SignInOutVo.OperationEnum.SIGN_IN.getType().equals(signInOutVo.getOperationType())){
            //如果是第一次签到 则改变状态为已签到
            if(VisitorApplyRecordStatusEnum.PASS.getStatusCode().equals(passedOrder.getStatus())) {
                passedOrder.setStatus(VisitorApplyRecordStatusEnum.SIGN_IN.getStatusCode());
                operationRecord.setNewStatus(passedOrder.getStatus());
            }

            //操作表 签到签退表
            operationRecord.setOperationType(VisitorRecordOperationEnum.SIGN_IN.getOperationCode());
            signRecord.setSignType(SignInOutVo.OperationEnum.SIGN_IN.getType());
        }
        //签退
        else if(SignInOutVo.OperationEnum.SIGN_OUT.getType().equals(signInOutVo.getOperationType())){
            //如果还没有签到则不能签退
            if(!VisitorApplyRecordStatusEnum.SIGN_IN.getStatusCode().equals(passedOrder.getStatus())
                    && !VisitorApplyRecordStatusEnum.SIGN_OUT.getStatusCode().equals(passedOrder.getStatus())){
                throw new BaseException(-1,"请先签到后进行签退操作！");
            }

            //如果是第一次签退，则改变状态为已签退
            if(VisitorApplyRecordStatusEnum.SIGN_IN.getStatusCode().equals(passedOrder.getStatus())){
                passedOrder.setStatus(VisitorApplyRecordStatusEnum.SIGN_OUT.getStatusCode());
                operationRecord.setNewStatus(passedOrder.getStatus());
            }

            //操作表 签到签退表
            operationRecord.setOperationType(VisitorRecordOperationEnum.SIGN_OUT.getOperationCode());
            signRecord.setSignType(SignInOutVo.OperationEnum.SIGN_OUT.getType());

        }
        else{
            throw new BaseException(-1,"操作类型异常！");
        }

        //操作记录其他信息
        operationRecord.setAdminFlag(GlobalConst.ADMIN_FLAG_FALSE);
        operationRecord.setRemark(signInOutVo.getRemark());
        operationRecord.setApplyFlag(GlobalConst.APPLY);
        operationRecord.setApplyRecordId(passedOrder.getId());
        operationRecord.setOperatorTime(DateTimeUtil.getTimeNow());
        operationRecord.setOperatorId(passedOrder.getVisitorInfoId());
        operationRecord.setOperatorName(visitor.getUsername());
        //操作记录入库
        operationRecord.insert();

        //申请单更新状态
        passedOrder.updateById();

        //重新设置订单信息进缓存
        cacheService.put(GlobalConst.VISITOR_PASS_CODE, key, passedOrder);

        //签到签退入库
        signRecord.insert();

        //返回信息
        VisitorApplyRecordDTO dto = new VisitorApplyRecordDTO();

        //健康信息
        HealthInfo health = healthInfoService.getById(passedOrder.getHealthInfoId());
        BeanUtils.copyProperties(health,dto);

        //图片
        List<Long> imgIdList = Arrays.asList(health.getHealthPictureId(), health.getTripPictureId(), health.getNucleicPictureId());
        List<FileUploadRecord> allImg = CollectionUtils.isEmpty(imgIdList) ? new ArrayList<>() : fileUploadRecordService
                .listByIds(imgIdList);

        BeanUtils.copyProperties(passedOrder,dto);
        dto.setHealthPicturePath(getPicPathById(health.getHealthPictureId(),allImg));
        dto.setNucleicPicturePath(getPicPathById(health.getNucleicPictureId(),allImg));
        dto.setTripPicturePath(getPicPathById(health.getTripPictureId(),allImg));

        //签到签退记录
        List<SignRecord> signRecordList = signRecordService
                .list(new QueryWrapper<SignRecord>().eq("visitor_apply_id", passedOrder.getVisitorInfoId()));
        List<OutInHistoryDTO.SignInOutDTO> signInOutDTOList = signRecordList
                .stream()
                .map(signInOut -> {
                    OutInHistoryDTO.SignInOutDTO signInOutDTO = new OutInHistoryDTO.SignInOutDTO();
                    BeanUtils.copyProperties(signInOut, signInOutDTO);
                    return signInOutDTO;
                })
                .sorted(Comparator.comparing(o -> DateTimeUtil.getDateByStr(o.getSignTime())))
                .collect(Collectors.toList());

        dto.setSignInOutList(signInOutDTOList);

        //操作记录
        List<OperationRecord> operationRecordList = operationRecordService
                .list(new QueryWrapper<OperationRecord>().eq("apply_record_id", passedOrder.getId()));
        List<OperationDTO> operationDTOList = operationRecordList.stream().map(record -> {
            OperationDTO operationDTO = new OperationDTO();
            BeanUtils.copyProperties(record, operationDTO);
            return operationDTO;
        }).collect(Collectors.toList());

        //访客信息
        VisitorInfoDTO visitorInfoDTO = new VisitorInfoDTO();
        if(null != visitor){
            BeanUtils.copyProperties(visitor, visitorInfoDTO);
            if(!StringUtils.isEmpty(visitor.getVehicleInf())){
                CarInformationVO informationVO = jsonService
                        .jsonToObject(visitor.getVehicleInf(), CarInformationVO.class);
                visitorInfoDTO.setPlateNumber(informationVO.getPlateNumber());
                visitorInfoDTO.setVehicleBrand(informationVO.getBrand());
            }
        }

        ApproverApproveRecordDTO retDTO = new ApproverApproveRecordDTO();
        retDTO.setVisitorApplyRecordDTO(dto);
        retDTO.setOperationDTO(operationDTOList);
        retDTO.setVisitorInfoDTO(visitorInfoDTO);

        return retDTO;

    }

    private String getPicPathById(Long id,List<FileUploadRecord> allImg){
        return allImg.stream().filter(img -> img.getId().equals(id)).map(FileUploadRecord::getFilePath).findAny().orElse(null);
    }
}




